#include<cstdio>
#include<iostream>
#include<sys/select.h>
#include<string>
#include<vector>
#include "tcpsocket.hpp"

// 用来封装实现 select

class Select{
private:
  int _maxfd; //最大描述符
  fd_set _rfds;  //可读事件的描述符集合
public:
  Select():_maxfd(-1){ FD_ZERO(&_rfds);}
  bool Add(TcpSocket sock){
      int fd=sock.GetFd();  
     //添加一个描述符到集合中
    FD_SET(fd,&_rfds);
    //修改最大描述符
    _maxfd = _maxfd > fd ? _maxfd : fd;
    return true;
  }
  bool Del(TcpSocket sock){
     int fd=sock.GetFd();  
    //删除一个描述符信息
    FD_CLR(fd,&_rfds);
    //更新最大描述符
    int i=_maxfd;
    for(i=_maxfd;i>=0;--i){
      if(FD_ISSET(i,&_rfds)){
        _maxfd=i;
       break;
      }
    }
    return true;
  }
  bool Wait(std::vector<TcpSocket>* active_socket,int timeout){
     //开始监控
     fd_set tmp_set=_rfds;    //临时集合
         //因为每次 select 监控可读集合时，都会将可读集合重置，因此我们需要临时拷贝一份可读集合来操作     
     struct timeval tv;
     tv.tv_sec=timeout;       //秒
     tv.tv_usec=0;           //微秒
     
     int ret=select(_maxfd+1,&tmp_set,NULL,NULL,&tv);
     if(ret==-1){
       perror("select error!\n");
       return false;
     }else if(ret==0){
         //超时
      active_socket->clear();    //清空描述符
      return true;
     }
     //描述符就绪
     for(int i=0;i<=_maxfd;++i){
        if(FD_ISSET(i,&tmp_set)){
           TcpSocket sock;
           sock.SetFd(i);         //设置就绪描述符
           active_socket->push_back(sock);
        }
     }
     return true;
  }
};








